
package JET.Centers.Scripts;

import JET.Centers.ControlCenter;
import JET.Scene;
import JET.physics.engine.JETContext;
import JET.physics.SBCollision;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

/**
 *
 * @author 057Ry
 */
public class ScriptsCenter {

    static final ControlCenter CC = ControlCenter.getInstance();
    ArrayList<MyScript> scripts;

    private ScriptEngine jsEngine;

    // This are complied sripts that notifies JetSystem listeners on jet system events
    private CompiledScript onStepScript;
    private CompiledScript onPrePaintScript;
    private CompiledScript onPostPaintScript;
    private CompiledScript onKeyUpScript;
    private CompiledScript onKeyDownScript;
    private CompiledScript onKeyTypedScript;
    private CompiledScript onBodyCollisionScript;

    private Scene scene;

    public ScriptsCenter(Scene scene) {
        scripts = new ArrayList<MyScript>();
        this.scene = scene;
        initJSEngine();
    }

    public void initJSEngine() {
        ScriptEngineManager scriptManager = new ScriptEngineManager();
        jsEngine = scriptManager.getEngineByExtension("js");
        System.out.println("jsEngine: "+jsEngine);

        jsEngine.put("CC", CC);
        
//        if (scene.getEngine() != null)
//            jsEngine.put("Scene", scene.getEngine());
//        jsEngine.put("jsEngine", jsEngine);
        
        // Execute js code enabling jet js events
        try {
            // Inject api to register simulation system listeners
            InputStream is = this.getClass().getResourceAsStream("/JET/Centers/Scripts/JetEvents.js");
            BufferedReader reader = new BufferedReader ( new InputStreamReader ( is ) );
            jsEngine.eval(reader, jsEngine.getContext());

            // Make some classes availiable by shorter names ...
            is = this.getClass().getResourceAsStream("/JET/Centers/Scripts/PackegesAndClassesInit.js");
            reader = new BufferedReader ( new InputStreamReader ( is ) );
            jsEngine.eval(reader, jsEngine.getContext());

            Compilable compilingEngine = (Compilable) jsEngine;
            onStepScript = compilingEngine.compile("JetSystem.callOnStepListeners();");
            onPrePaintScript = compilingEngine.compile("JetSystem.callOnPrePaintListeners();");
            onPostPaintScript = compilingEngine.compile("JetSystem.callOnPostPaintListeners();");
            onBodyCollisionScript = compilingEngine.compile("JetSystem.callOnBodyCollisionListeners();");
        } catch (Exception ex) {ex.printStackTrace();}
    }

    public ScriptEngine getJsEngine() {
        return jsEngine;
    }

    public void clear() {
        scripts.clear();
    }

    public ArrayList<MyScript> getScripts() {
        return scripts;
    }

    public Collection<MyScript> getScriptsSync() {
        return Collections.synchronizedList(scripts);
    }

    public int getScriptsCount() {
        return scripts.size();
    }

    public void addScript(MyScript script) {
        if (!scripts.contains(script))
            scripts.add(script);
    }

    public void addScript(int index, MyScript script) {
        if (!scripts.contains(script))
            scripts.add(index, script);
    }

    public MyScript getScript(int index) {
        if (index>=0 && index<scripts.size())
            return scripts.get(index);
        else
            return null;
    }

    public MyScript getScript(String name) {
        for (MyScript s : scripts)
            if (s.getName().equals(name))
                return s;

        return null;
    }

    public int getScriptIndex(MyScript s) {
        return scripts.indexOf(s);
    }

    public void removeScript(int index) {
        scripts.remove(index);
    }

    public void removeScript(MyScript script) {
        scripts.remove(script);
    }

    public void compileAll() {
        for(MyScript s : scripts)
            //if (!s.isCompiled())
                s.compile(jsEngine, CC);
    }

    public void executeAll() {
        for(MyScript s : scripts)
            s.execute(jsEngine, CC);
    }

    ////////////////////////////////////////////////////////////////////////////
    //                J E T   S Y S T E M   N O T I F Y I N G                 //
    ////////////////////////////////////////////////////////////////////////////

    public void notifyOnStep() {
        try{
            onStepScript.eval(jsEngine.getContext());
        } catch(Exception e) {
            CC.GUIC.printlnToOutput("[Ex] System Exception while executing system onStep script.");
            CC.GUIC.printlnToOutput(e.getMessage());
            e.printStackTrace();
        }
    }
    public void notifyOnPrePaint() {
        try{
            onPrePaintScript.eval(jsEngine.getContext());
        } catch(Exception e) {
            CC.GUIC.printlnToOutput("[Ex] System Exception while executing system onPrePaint script.");
            CC.GUIC.printlnToOutput(e.getMessage());
            e.printStackTrace();
        }
    }
    public void notifyOnPostPaint() {
        try{
            onPostPaintScript.eval(jsEngine.getContext());
        } catch(Exception e) {
            CC.GUIC.printlnToOutput("[Ex] System Exception while executing system onPostPaint script.");
            CC.GUIC.printlnToOutput(e.getMessage());
            e.printStackTrace();
        }
    }
    public void notifyOnBodyCollision(SBCollision col, int index) {
        try {
            //onBodyCollisionScript.eval(jsEngine.getContext());

            jsEngine.eval("JetSystem.callOnBodyCollisionListeners(\""+ col.body1.getName() +"\",\""+ col.body2.getName() +"\", "+index+")");
        } catch(Exception e) {
            CC.GUIC.printlnToOutput("[Ex] System Exception while executing system onBodyCollision script.");
            CC.GUIC.printlnToOutput(e.getMessage());
            e.printStackTrace();
        }
    }

}